package com.yang.api.controller;


import com.yang.api.filter.CheckFilterContext;
import com.yang.api.form.SingleSendForm;
import com.yang.api.utils.R;
import com.yang.api.vo.ResultVO;

import com.yang.common.constant.RabbitMQConstants;
import com.yang.common.enums.ExceptionEnums;
import com.yang.common.model.StandardSubmit;
import com.yang.common.util.LogUtil;
import com.yang.common.util.SnowFlakeUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.Map;

/**
 * 短信发送接口
 */
@RestController
@RequestMapping("/sms") //v1请求路径在网关中添加
@Slf4j
public class SmsController {

    /**
     * 客户端IP地址的请求头信息，多个用','隔开。
     */
    @Value("${headers}")
    private String headers;

    /**
     * 基于请求头获取信息时，可能获取到的未知信息
     */
    private final String UNKNOW = "unknow";

    /**
     * 如果是当前请求头获取IP地址，需要截取到第一个','位置
     */
    private final String X_FORWARDED_FOR = "x-forwarded-for";

    @Autowired
    private CheckFilterContext checkFilterContext;

    /**
     * 雪花算法工具类
     */
    @Autowired
    private SnowFlakeUtil snowFlakeUtil;

    /**
     * rabbitMQ
     */
    @Autowired
    private RabbitTemplate rabbitTemplate;


    /**
     * 功能:单条短信发送接口
     * 请求路径:https://sms.beaconcloud.com/v1/sms/single_send
     *
     * @param singleSendForm 实体类SingleSendForm，封装请求参数
     * @return 返回结果的ResultVO，提供的R工具类
     */
    @PostMapping(value = "single_send", produces = "application/json;charset=utf-8")
//produces属性表示响应客户端时所使用的内容类型（Content-Type）
    public ResultVO singleSend(@RequestBody @Validated SingleSendForm singleSendForm, BindingResult bindingResult, HttpServletRequest req) {
        if (bindingResult.hasErrors()) {//hasErrors()方法表示有一个不满足就会返回true
            String msg = bindingResult.getFieldError().getDefaultMessage();//获取JSR-303注解的message
            log.info("【接口模块-单条短信Controller】 参数不合法 msg = {}", msg);
            return R.error(ExceptionEnums.PARAMETER_ERROR.getCode(), msg);
        }

        //获取真实的ip地址
        String realIP = this.getRealIP(req);

        //构建StandardSubmit，各种封装校验
        StandardSubmit submit = new StandardSubmit();
        submit.setRealIP(realIP);
        submit.setApikey(singleSendForm.getApikey());
        submit.setMobile(singleSendForm.getMobile());
        submit.setText(singleSendForm.getText());
        submit.setState(singleSendForm.getState());
        submit.setUid(singleSendForm.getUid());

        //调用策略模式的校验链
        checkFilterContext.check(submit);

        //基于雪花算法生成唯一id，并添加到StandardSubmit对象中
        submit.setSequenceId(snowFlakeUtil.nextId());

        //设置发送时间
        submit.setSendTime(LocalDateTime.now());

        //发送到MQ，交给策略模块处理
        //入参依次是：1.队列名称 2.消息 3.CorrelationData中封装消息id，消息id采用雪花算法生成的id
        rabbitTemplate.convertAndSend(RabbitMQConstants.SMS_PRE_SEND,submit,new CorrelationData(submit.getSequenceId().toString()));

        //返回接收成功
        return R.ok();
    }

    //获取真实ip，根据nacos配置文件中动态的按照顺序通过请求头获取ip
    private String getRealIP(HttpServletRequest req) {
        //1.声明返回的ip地址
        String ip = "";

        //2. 遍历请求头，并且通过req获取ip地址
        for (String header : headers.split(",")) {
            // 健壮性校验
            if (StringUtils.isNotBlank(header)) {
                // 基于req获取ip地址
                ip = req.getHeader(header);
                //健壮性判断，判断请求头是否是x-forwarded-for
                if (StringUtils.isNotBlank(ip) && !UNKNOW.equalsIgnoreCase(ip)) {
                    if (X_FORWARDED_FOR.equalsIgnoreCase(header) && ip.indexOf(",") > 0) {
                        ip = ip.substring(0, ip.indexOf(","));
                    }
                    return ip;
                }
            }
        }

        //3. 如果请求头都没有获取到IP地址，直接基于传统的方式获取一个IP
        return req.getRemoteAddr();
    }
}
